#ifndef __parse_info_H__
#define __parse_info_H__

#include "syntax_base.h"
#include "callstack.h"

#ifdef _WIN32
#pragma warning(disable:4786)
#endif

#include <iostream>
#include <list>
using namespace std;

namespace syntax_analysis
{
	class language;

	class parse_para
	{
	public:
		parse_para()
		{
			m_lang = NULL;
			m_code = NULL;
			m_acceptted.clear();
			m_parsed = false;
		}

		parse_para( language *lang, char *code, const list<pair<syntax*,int> > &acceptted )
		{
			m_lang = lang;
			m_code = code;
			m_acceptted = acceptted;
			m_parsed = false;
		}

		virtual ~parse_para()
		{
			m_lang = NULL;
			m_code = NULL;
			m_acceptted.clear();
		}

		void reset( char *code )
		{
			m_code = code;
			m_acceptted.clear();
			m_parsed = false;
		}

	public:
		char* get_code()
		{
			return m_code;
		}

		char* get_last_start_code()
		{
			return m_code + get_acceptted( get_acceptted_count() - 1 );
		}

		void set_code( char *code )
		{
			m_code = code;
		}

		const list<pair<syntax*,int> >& get_acceptted()
		{
			return m_acceptted;
		}

		void set_acceptted( const list<pair<syntax*,int> > &acceptted )
		{
			m_acceptted = acceptted;
		}

		bool add_acceptted( syntax *syn, int acceptted, bool no_repeat = true )
		{
			if( no_repeat && m_acceptted.size() > 0 )
			{
				list<pair<syntax*,int> >::iterator i;
				for( i = m_acceptted.begin(); i != m_acceptted.end(); ++i )
				{
					if( acceptted == i->second )
						return false;
				}
			}
			m_acceptted.push_back( pair<syntax*,int>( syn, acceptted ) );
			return true;
		}

		int get_acceptted( int pos )
		{
			list<pair<syntax*,int> >::iterator it = m_acceptted.begin();
			if( pos > m_acceptted.size() )
				return 0;
			advance( it, pos );
			if( it != m_acceptted.end() )
				return it->second;
			else
				return 0;
		}
		
		syntax* get_acceptted_syn( int pos )
		{
			list<pair<syntax*,int> >::iterator it = m_acceptted.begin();
			if( pos > m_acceptted.size() )
				return NULL;
			advance( it, pos );
			if( it != m_acceptted.end() )
				return it->first;
			else
				return NULL;
		}

		void remove_last_acceptted()
		{
			if( m_acceptted.size() > 0 )
				m_acceptted.erase( --m_acceptted.end() );
		}

		int get_acceptted_count()
		{
			return m_acceptted.size();
		}

		language* get_language()
		{
			return m_lang;
		}

		void set_language( language *lang )
		{
			m_lang = lang;
		}

		bool parsed()
		{
			return m_parsed;
		}

		void set_parsed( )
		{
			m_parsed = true;
		}

		callstack get_callstack();
		syntax* pop_call();
		void push_call( syntax *syn );

		bool operator==( const parse_para &para ) const
		{
			if( m_lang != para.m_lang )
				return false;
			if( m_code != para.m_code )
				return false;
			if( m_parsed != para.m_parsed )
				return false;
			if( m_acceptted.size() != para.m_acceptted.size() )
				return false;
			list<pair<syntax*,int> >::const_iterator i, j;
			for( i = m_acceptted.begin(), j = para.m_acceptted.begin();
				i != m_acceptted.end();
				++i, ++j )
				{
					if( i->second != j->second )
						return false;
				}
			return true;
		}

		const parse_para& operator=( const parse_para &para )
		{
			m_code = para.m_code;
			m_acceptted = para.m_acceptted;
			m_lang = para.m_lang;
			m_parsed = para.m_parsed;
			return *this;
		}

		void print( int level )
		{
			list<pair<syntax*,int> >::iterator i;
			for( i = m_acceptted.begin(); i != m_acceptted.end(); ++i )
			{
				int j;
				for( j = 0; j < level; ++j )
					cout << " ";
				cout << i->first->to_string() << endl;
			}
		}

	private:
		char *m_code;
		list<pair<syntax*,int> > m_acceptted;
		language *m_lang;
		bool m_parsed;
	};

	class parse_info
	{
	public:
		parse_info()
		{
			m_child.clear();
			m_para = NULL;
			m_parent = NULL;
		}

		parse_info( const list<parse_info*> &child, parse_para *para )
		{
			m_child = child;
			m_para = para;
		}

		virtual ~parse_info()
		{
			list<parse_info*>::iterator i;
			for( i = m_child.begin(); i != m_child.end(); ++i )
				delete *i;
			if( m_para != NULL )
				delete m_para;

			m_child.clear();
			m_para = NULL;
		}

		void reset( char *code )
		{
			if( m_para )
				m_para->reset( code );
			list<parse_info*>::iterator i;
			for( i = m_child.begin(); i != m_child.end(); ++i )
				(*i)->reset( code );
		}

	public:
		const list<parse_info*>& get_child()
		{
			return m_child;
		}

		void set_child( const list<parse_info*> &child )
		{
			list<parse_info*>::iterator i;
			for( i = m_child.begin(); i != m_child.end(); ++i )
				delete *i;

			m_child = child;
		}

		parse_para* get_parse_para()
		{
			return m_para;
		}

		void set_parse_para( parse_para *para )
		{
			if( m_para != NULL )
				delete m_para;
			m_para = para;
		}

		parse_info* get_child( int pos )
		{
			list<parse_info*>::iterator i;
			i = m_child.begin();
			if( pos > m_child.size() )
				return NULL;

			advance( i, pos );
			if( i != m_child.end() )
				return *i;
			else
				return NULL;
		}

		void remove_child( int pos )
		{
			list<parse_info*>::iterator i;
			i = m_child.begin();
			if( pos <= m_child.size() )
			{
				advance( i, pos );
				if( i != m_child.end() )
				{
					delete *i;
					m_child.erase( i );
				}
			}
		}

		void clear_child()
		{
			list<parse_info*>::iterator i;
			for( i = m_child.begin(); i != m_child.end(); ++i )
				delete *i;
			m_child.clear();
		}

		void add_child( parse_info *child )
		{
			m_child.push_back( child );
		}

		parse_info* create_child( char *code, language *lang )
		{
			parse_para *child_para;
			parse_info *child_info;

			child_para = new parse_para();
			child_para->set_code( code );
			child_para->set_language( lang );
			child_info = new parse_info();
			child_info->set_parse_para( child_para );
			child_info->m_parent = this;
			add_child( child_info );

			return child_info;
		}

		bool operator==( const parse_info &info ) const
		{
			if( m_child.size() != info.m_child.size() )
				return false;
			if( !(*m_para == *info.m_para) )
				return false;
			list<parse_info*>::const_iterator i,j;
			for( i = m_child.begin(), j = info.m_child.begin();
				i != m_child.end();
				++i, ++j )
				{
					if( !(*(*i)==*(*j)) )
						return false;
				}
			return true;
		}

		const parse_info& operator=( const parse_info &info )
		{
			clear_child();
			if( m_para != NULL )
				delete m_para;
			m_para = NULL;
			if( info.m_para != NULL )
			{
				m_para = new parse_para();
				*m_para = *info.m_para;
			}
			list<parse_info*>::const_iterator i;
			for( i = info.m_child.begin(); i != info.m_child.end(); ++i )
			{
				parse_info *child;
				child = new parse_info();
				*child = *(*i);
				m_child.push_back( child );
			}
			return *this;
		}

		void print( int level )
		{
			m_para->print( level );
			list<parse_info*>::iterator i;
			for( i = m_child.begin(); i != m_child.end(); ++i )
				(*i)->print( level + 1 );
		}

		parse_info* get_root()
		{
			parse_info *root;
			root = this;
			while( root->m_parent != NULL )
				root = root->m_parent;
			return root;
		}

	private:
		list<parse_info*> m_child;
		parse_para *m_para;
		parse_info *m_parent;
	};
}

#endif // __parse_info_h__
